package com.lz.aop.bean;
/**
 * sfds..
 *
 * @author Lizhong
 * @date 2019/6/6
 */

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;


//把这个类声明为一个切面
//1.需要将该类放入到IOC 容器中
@Component
//2.再声明为一个切面
@Aspect
public class LoggingAspect {
    //声明该方法是一个前置通知：在目标方法开始之前执行 哪些类，哪些方法
    //作用：@before 当调用目标方法，而目标方法与注解声明的方法相匹配的时候，aop框架会自动的为那个方法所在的类生成一个代理对象，在目标方法执行之前，执行注解的方法
    //支持通配符
    //@Before("execution(public int com.lz.aop.bean.ArithmeticCaculatorImpl.*(..))")
    @Before("execution(* com.lz.aop.bean.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " begins " + args);
    }

    @After("execution(* com.lz.aop.bean.*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method " + methodName + " end " + args);
    }


    @AfterReturning(value = "execution(* com.lz.aop.bean.*.*(..))", returning = "result0")
    public void afterReturning(JoinPoint joinPoint, Object result0) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " end with " + result0);
    }

    @AfterThrowing(value = "execution(* com.lz.aop.bean.*.*(..))", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("The method " + methodName + " occurs exceptions " + ex);
    }

    /**
     *
     *  环绕通知需要携带 ProceedingJoinPoint 类型的参数
     *                    环绕通知 类似于  动态代理的全过程
     *                   ProceedingJoinPoint：可以决定是否执行目标方法
     *    环绕通知必须有返回值，返回值即为目标方法的返回值
     *
     * @param proceedingJoinPoint
     */
    @Around("execution(* com.lz.aop.bean.*.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {

        Object result = null;
        String methodName = proceedingJoinPoint.getSignature().getName();
        //执行目标方法
        try {
            //前置通知
            System.out.println("around: The method " + methodName + " begin with " + Arrays.asList(proceedingJoinPoint.getArgs()));

            result = proceedingJoinPoint.proceed();
            // 异常时此处不执行
            //后置通知
            System.out.println("around: The method " + methodName + " end with " + result);

        } catch (Throwable e) {
            //异常通知
            System.out.println("around: The method " + methodName + " occurs exception : " + e);
            throw new RuntimeException();
        }
        //后置通知

        System.out.println("around: The method " + methodName + " end with " + result);

        return result;

    }


}